import { createAlova } from 'alova'
import type { BodyOptions, QueryOptions } from '../global.d'
import vueHook from 'alova/vue'
import fetchAdapter from 'alova/fetch'

const alovaInstance = createAlova({
  baseURL: '/api',
  statesHook: vueHook,
  cacheFor: null,
  requestAdapter: fetchAdapter(),
  beforeRequest: (method) => {
    method.config.headers['Content-Type'] = 'application/json'
  },
  responded: async (response) => {
    const res = await response.json()

    if (!res.data) {
      res.data = {
        ...res,
      }
    }
    return res.data
  },
})

export default alovaInstance

class Http {
  delete(url: string, data?: QueryOptions) {
    return this.request('delete', url, data)
  }

  get(url: string, data?: QueryOptions) {
    return this.request('get', url, data)
  }

  patch(url: string, data?: BodyOptions) {
    return this.request('patch', url, data)
  }

  post(url: string, data?: BodyOptions) {
    return this.request('post', url, data)
  }

  put(url: string, data?: BodyOptions) {
    return this.request('put', url, data)
  }

  private appendParamsToUrl(url: string, params: any): string {
    let queryString = ''
    for (const key in params) {
      if (Object.prototype.hasOwnProperty.call(params, key)) {
        queryString += `${queryString ? '&' : '?'}${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`
      }
    }
    return url + queryString
  }

  private isBodyOptions(options: BodyOptions | QueryOptions): options is BodyOptions {
    return (options as BodyOptions).data !== undefined
  }

  /**
   * 适配swagger路径参数，针对于pathParams
   * 输入参数 "/api/v1/user/{id}",{ pathParams:{ id :1 },params:{ id:2 } }
   * 输出请求 /api/v1/user/1?id=2
   */
  private replacePathParams(url: string, pathParams?: any): string {
    if (!pathParams) return url
    return url.replaceAll(/\{(\w+)\}/g, (_, key) => pathParams[key] || `{${key}}`)
  }

  private request(method: string, url: string, data?: BodyOptions | QueryOptions): Promise<any> {
    let finalUrl = this.replacePathParams(url, data?.pathParams)
    const config = data?.config || {}

    // 当组件使用allowClear属性时，会将数据置为null，导致数据查询失败
    if (data && data.params) {
      Object.keys(data.params).forEach((key) => {
        if (data.params[key] === null || data.params[key] === undefined) {
          delete data.params[key]
        }
      })
    }
    if (data && this.isBodyOptions(data)) {
      Object.keys(data.data).forEach((key) => {
        if (data.data[key] === null || data.data[key] === undefined) {
          delete data.data[key]
        }
      })
    }

    let alovaMethod: 'Delete' | 'Get' | 'Post' | 'Put' = 'Get'

    if (method === 'get' || method === 'delete') {
      if (method === 'get') {
        alovaMethod = 'Get'
      }
      if (method === 'delete') {
        alovaMethod = 'Delete'
      }
      return alovaInstance[alovaMethod](finalUrl, {
        ...config,
        params: data?.params,
      })
    } else {
      // 处理 params 到 url 的逻辑
      if (data?.params) {
        finalUrl = this.appendParamsToUrl(finalUrl, data.params)
      }
      if (method === 'post') {
        alovaMethod = 'Post'
      }
      if (method === 'put') {
        alovaMethod = 'Put'
      }

      return alovaInstance[alovaMethod](finalUrl, data?.data, { ...config })
    }
  }
}

export const http = new Http()
